#region Using

using System;
using System.Xml;
using System.IO;
using System.Globalization;
using System.Collections.Generic;
using System.Collections.Specialized;
using BlogEngine.Core;
using BlogEngine.Core.Provider.Interfaces;

#endregion

namespace BlogEngine.Core.Provider.XML
{
	/// <summary>
	/// A storage provider for BlogEngine that uses XML files.
	/// <remarks>
	/// To build another provider, you can just copy and modify
	/// this one. Then add it to the web.config's BlogEngine section.
	/// </remarks>
	/// </summary>
	public class CIPhotos : IPhotos
	{
		
		/// <summary>
		/// Retrieves a photo based on the specified Id.
		/// </summary>
		public Photo Select(Guid id)
		{
			string fileName = Provider.Folder + "photos" + Path.DirectorySeparatorChar + id.ToString() + ".xml";
			Photo photo = new Photo();
			XmlDocument doc = new XmlDocument();
			doc.Load(fileName);

			photo.Title = doc.SelectSingleNode("photo/title").InnerText;
			photo.Description = doc.SelectSingleNode("photo/description").InnerText;
			photo.Content = doc.SelectSingleNode("photo/content").InnerText;
			photo.DateCreated = DateTime.Parse(doc.SelectSingleNode("photo/pubdate").InnerText, CultureInfo.InvariantCulture);
			photo.DateModified = DateTime.Parse(doc.SelectSingleNode("photo/lastmodified").InnerText, CultureInfo.InvariantCulture);

			if (doc.SelectSingleNode("photo/author") != null)
				photo.Author = doc.SelectSingleNode("photo/author").InnerText;

			if (doc.SelectSingleNode("photo/ispublished") != null)
				photo.IsPublished = bool.Parse(doc.SelectSingleNode("photo/ispublished").InnerText);

			if (doc.SelectSingleNode("photo/location") != null)
				photo.Location = doc.SelectSingleNode("photo/location").InnerText;

			if (doc.SelectSingleNode("photo/iscommentsenabled") != null)
				photo.IsCommentsEnabled = bool.Parse(doc.SelectSingleNode("photo/iscommentsenabled").InnerText);

			if (doc.SelectSingleNode("photo/order") != null)
				photo.Order = int.Parse(doc.SelectSingleNode("photo/order").InnerText, CultureInfo.InvariantCulture);

			if (doc.SelectSingleNode("photo/raters") != null)
				photo.Raters = int.Parse(doc.SelectSingleNode("photo/raters").InnerText, CultureInfo.InvariantCulture);

			if (doc.SelectSingleNode("photo/rating") != null)
				photo.Rating = float.Parse(doc.SelectSingleNode("photo/rating").InnerText, System.Globalization.CultureInfo.GetCultureInfo("en-gb"));

			if (doc.SelectSingleNode("photo/slug") != null)
				photo.Slug = doc.SelectSingleNode("photo/slug").InnerText;

			if (doc.SelectSingleNode("photo/originalfilename") != null)
				photo.OriginalFileName = doc.SelectSingleNode("photo/originalfilename").InnerText;

			if (doc.SelectSingleNode("photo/photodate") != null)
				photo.PhotoDate = DateTime.Parse(doc.SelectSingleNode("photo/photodate").InnerText, CultureInfo.InvariantCulture);

			if (doc.SelectSingleNode("photo/width") != null)
				photo.Width = int.Parse(doc.SelectSingleNode("photo/width").InnerText, CultureInfo.InvariantCulture);

			if (doc.SelectSingleNode("photo/height") != null)
				photo.Height = int.Parse(doc.SelectSingleNode("photo/height").InnerText, CultureInfo.InvariantCulture);

			if (doc.SelectSingleNode("photo/filesize") != null)
				photo.FileSize = long.Parse(doc.SelectSingleNode("photo/filesize").InnerText, CultureInfo.InvariantCulture);

			if (doc.SelectSingleNode("photo/md5hash") != null)
				photo.MD5Hash = doc.SelectSingleNode("photo/md5hash").InnerText;

			if (doc.SelectSingleNode("photo/albumid") != null)
				photo.Album = Album.GetById(new Guid(doc.SelectSingleNode("photo/albumid").InnerText));

			// Tags
			foreach (XmlNode node in doc.SelectNodes("photo/tags/tag"))
			{
				if (!string.IsNullOrEmpty(node.InnerText))
					photo.Tags.Add(node.InnerText);
			}

			// comments
			foreach (XmlNode node in doc.SelectNodes("photo/comments/comment"))
			{
				Comment comment = new Comment();
				comment.Id = new Guid(node.Attributes["id"].InnerText);
				comment.Author = node.SelectSingleNode("author").InnerText;
				comment.Email = node.SelectSingleNode("email").InnerText;
				comment.Parent = photo;

				if (node.SelectSingleNode("country") != null)
					comment.Country = node.SelectSingleNode("country").InnerText;

				if (node.SelectSingleNode("ip") != null)
					comment.IP = node.SelectSingleNode("ip").InnerText;

				if (node.SelectSingleNode("website") != null)
				{
					Uri website;
					if (Uri.TryCreate(node.SelectSingleNode("website").InnerText, UriKind.Absolute, out website))
						comment.Website = website;
				}

				if (node.Attributes["approved"] != null)
					comment.IsApproved = bool.Parse(node.Attributes["approved"].InnerText);
				else
					comment.IsApproved = true;

				comment.Content = node.SelectSingleNode("content").InnerText;
				comment.DateCreated = DateTime.Parse(node.SelectSingleNode("date").InnerText, CultureInfo.InvariantCulture);
				photo.Comments.Add(comment);
			}

			photo.Comments.Sort();

			// categories
			foreach (XmlNode node in doc.SelectNodes("photo/categories/category"))
			{
				Guid key = new Guid(node.InnerText);
				Category cat = Category.GetById(key);
				if (cat != null)
					photo.Categories.Add(cat);
			}

			// photo effects
			foreach (XmlNode node in doc.SelectNodes("photo/photoeffects/photoeffect"))
			{
				Guid key = new Guid(node.InnerText);
				PhotoEffect photoeffect = PhotoEffect.GetById(key);
				if (photoeffect != null)
					photo.PhotoEffects.Add(photoeffect);
			}

			return photo;
		}

		/// <summary>
		/// Inserts a new Photo to the data store.
		/// </summary>
		/// <param name="photo"></param>
		public void Insert(Photo photo)
		{
			if (!Directory.Exists(Provider.Folder + "photos"))
				Directory.CreateDirectory(Provider.Folder + "photos");

			string fileName = Provider.Folder + "photos" + Path.DirectorySeparatorChar + photo.Id.ToString() + ".xml";
			XmlWriterSettings settings = new XmlWriterSettings();
			settings.Indent = true;

			using (XmlWriter writer = XmlWriter.Create(fileName, settings))
			{
				writer.WriteStartDocument(true);
				writer.WriteStartElement("photo");
				writer.WriteAttributeString("id", photo.Id.ToString());

				writer.WriteElementString("author", photo.Author);
				writer.WriteElementString("title", photo.Title);
				writer.WriteElementString("description", photo.Description);
				writer.WriteElementString("content", photo.Content);
				writer.WriteElementString("ispublished", photo.IsPublished.ToString());
				writer.WriteElementString("location", photo.Location);
				writer.WriteElementString("iscommentsenabled", photo.IsCommentsEnabled.ToString());
				writer.WriteElementString("pubdate", photo.DateCreated.AddHours(-BlogSettings.Instance.Timezone).ToString("yyyy-MM-dd HH:mm:ss", CultureInfo.InvariantCulture));
				writer.WriteElementString("lastmodified", photo.DateModified.AddHours(-BlogSettings.Instance.Timezone).ToString("yyyy-MM-dd HH:mm:ss", CultureInfo.InvariantCulture));
				writer.WriteElementString("order", photo.Order.ToString(CultureInfo.InvariantCulture));
				writer.WriteElementString("raters", photo.Raters.ToString(CultureInfo.InvariantCulture));
				writer.WriteElementString("rating", photo.Rating.ToString(CultureInfo.InvariantCulture));
				writer.WriteElementString("slug", photo.Slug);
				writer.WriteElementString("originalfilename", photo.OriginalFileName);
				writer.WriteElementString("photodate", photo.PhotoDate.AddHours(-BlogSettings.Instance.Timezone).ToString("yyyy-MM-dd HH:mm:ss", CultureInfo.InvariantCulture));
				writer.WriteElementString("width", photo.Width.ToString());
				writer.WriteElementString("height", photo.Height.ToString());
				writer.WriteElementString("filesize", photo.FileSize.ToString());
				writer.WriteElementString("md5hash", photo.MD5Hash);
				writer.WriteElementString("albumid", photo.Album.Id.ToString());

				// Tags
				writer.WriteStartElement("tags");
				foreach (string tag in photo.Tags)
				{
					writer.WriteElementString("tag", tag);
				}
				writer.WriteEndElement();

				// comments
				writer.WriteStartElement("comments");
				foreach (Comment comment in photo.Comments)
				{
					writer.WriteStartElement("comment");
					writer.WriteAttributeString("id", comment.Id.ToString());
					writer.WriteAttributeString("approved", comment.IsApproved.ToString());
					writer.WriteElementString("date", comment.DateCreated.AddHours(-BlogSettings.Instance.Timezone).ToString("yyyy-MM-dd HH:mm:ss", CultureInfo.InvariantCulture));
					writer.WriteElementString("author", comment.Author);
					writer.WriteElementString("email", comment.Email);
					writer.WriteElementString("country", comment.Country);
					writer.WriteElementString("ip", comment.IP);
					if (comment.Website != null)
						writer.WriteElementString("website", comment.Website.ToString());
					writer.WriteElementString("content", comment.Content);
					writer.WriteEndElement();
				}
				writer.WriteEndElement();

				// categories
				writer.WriteStartElement("categories");
				foreach (Category cat in photo.Categories)
				{
					//if (cat.Id = .Instance.ContainsKey(key))
					//     writer.WriteElementString("category", key.ToString());
					writer.WriteElementString("category", cat.Id.ToString());

				}
				writer.WriteEndElement();

				// photo effects
				writer.WriteStartElement("photoeffects");
				foreach (PhotoEffect photoeffect in photo.PhotoEffects)
					writer.WriteElementString("photoeffect", photoeffect.Id.ToString());
				writer.WriteEndElement();

				writer.WriteEndElement();
			}

			if (!Photo.Items.Contains(photo))
				Photo.Items.Add(photo);

			Photo.Items.Sort();
		}

		/// <summary>
		/// Updates a Photo.
		/// </summary>
		public void Update(Photo photo)
		{
			Insert(photo);
		}

		/// <summary>
		/// Deletes a photo from the data store.
		/// </summary>
		public void Delete(Photo photo)
		{
			if (Photo.Items.Contains(photo))
				Photo.Items.Remove(photo);

			string fileName = Provider.Folder + "photos" + Path.DirectorySeparatorChar + photo.Id.ToString() + ".xml";
			if (File.Exists(fileName))
				File.Delete(fileName);
		}

		/// <summary>
		/// Retrieves all photos from the data store
		/// </summary>
		/// <returns>List of Photos</returns>
		public List<Photo> Fill()
		{
			string folder = Provider.Folder + "photos" + Path.DirectorySeparatorChar;
			List<Photo> photos = new List<Photo>();

			foreach (string file in Directory.GetFiles(folder, "*.xml", SearchOption.TopDirectoryOnly))
			{
				FileInfo info = new FileInfo(file);
				string id = info.Name.Replace(".xml", string.Empty);
				Photo photo = Photo.Load(new Guid(id));
				photos.Add(photo);
			}

			photos.Sort();
			return photos;
		}

	}
}
